package com.mylater.nace.client;

import com.mylater.nace.compiler.ClassCompiler;
import com.mylater.nace.common.NaceThreadFactory;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;

public class HotSwapClient {

    // 因ChannelFactory的关闭有DirectMemory泄露，采用静态化规避
    // https://issues.jboss.org/browse/NETTY-424
    private static final ChannelFactory channelFactory = new NioClientSocketChannelFactory(
            Executors.newSingleThreadExecutor(new NaceThreadFactory("HotSwapClient_Boss", true)),
            Executors.newSingleThreadExecutor(new NaceThreadFactory("HotSwapClient_Worker", true)),
            1);

    public static void main(String[] args) {
        send(connect());
    }

    public static void send(ChannelFuture future) {
        if (future.isCancelled()) {
            // Connection attempt cancelled by user
            System.out.println("isCanncelled");
        } else if (!future.isSuccess()) {
            future.getCause().printStackTrace();
            System.out.println("isNotSuccess");
        } else {
            // Connection established successfully
            Channel channel = future.getChannel();
            channel.setInterestOps(Channel.OP_READ_WRITE);

            // 编译参数
            List<String> otherArgs = Arrays.asList("-classpath", HotSwapClient.class.getProtectionDomain().getCodeSource().getLocation().toString());
            // 编译
            byte[] classByte = ClassCompiler.callJavac(otherArgs, "HotSwap");
            ChannelBuffer buffer = ChannelBuffers.buffer(classByte.length + 4);
            buffer.writeInt(classByte.length);
            buffer.writeBytes(classByte);
            channel.write(buffer);
        }
    }

    public static ChannelFuture connect() {
        ClientBootstrap bootstrap = new ClientBootstrap(channelFactory);
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            @Override
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new SimpleChannelHandler() {

                    @Override
                    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
                        System.out.println("channelConnected");
                    }

                    @Override
                    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
                        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
                        System.out.println(buffer.toString(Charset.forName("UTF-8")));
                        System.out.flush();
                        e.getChannel().close();
                    }

                    @Override
                    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
                        System.out.println("client exceptionCaught");
                        e.getCause().printStackTrace();
                        e.getChannel().close();
                    }
                });
            }
        });
        bootstrap.setOption("tcpNoDelay", true);
        bootstrap.setOption("keepAlive", true);
        ChannelFuture future = bootstrap.connect(new InetSocketAddress("127.0.0.1", 20001));
        future.awaitUninterruptibly();
        return future;
    }
}
